home *** CD-ROM | disk | FTP | other *** search
/ Fritz: All Fritz / All Fritz.zip / All Fritz / FILES / MISCEOUS / YRCAL17T.LZH / YRCLMISC.C < prev    next >
Text File  |  1989-10-02  |  17KB  |  571 lines

  1. /********************************************************************
  2. **  YRCLMISC.C v0.17T  Copyright (c) 1987, 1988, 1989 by Paul M. Sittler.
  3. **  All rights reserved.  The copyright owner hereby authorizes the
  4. **  no-charge, noncommercial making and/or distribution of copies of
  5. **  the entirety of this work unchanged and unincorporated in any
  6. **  other work (except "LiBRary" or "ARChive" disk files for the sole
  7. **  purpose of no-charge noncommercial distribution).  No other
  8. **  reproduction or use is authorized without the express prior
  9. **  written consent of the copyright owner.
  10. **
  11. **************************************************************/
  12.  
  13. /* ANSI header files included:  */
  14. #include <stdio.h>    /* fputs, printf, sprintf, stderr */
  15. #include <ctype.h>    /* isdigit, tolower */
  16. #include <fcntl.h>    /* O_BINARY, O_RDWR */
  17. #include <io.h>        /* close, lseek, open, read, write */
  18. #include <stdlib.h>    /* atoi, exit */
  19. #include <string.h>    /* strcat, strcpy, strlen */
  20.  
  21. /* Turbo-C Header files included:  */
  22. #include <conio.h>    /* getch, putch */
  23.  
  24. #include "yearcal.def"
  25.  
  26. extern struct options Opt;        /* Declared in YEARCAL.C */
  27. extern FILE *fp;            /* Declared in YEARCAL.C */
  28. extern char *file;            /* Declared in YEARCAL.C */
  29. extern struct month mon[];        /* Declared in YEARCAL.C */
  30. extern int yr[][12][6][7];        /* Array for 3 yrs, 4-D, */
  31.  
  32.  
  33.  
  34.  
  35. char *center(char *str, int width)
  36. {
  37.     static char buf[BUF];        /* Location of finished string */
  38.     static char copy[BUF];        /* Copy of str to avoid side effects */
  39.  
  40.     char filler;
  41.     int i;
  42.  
  43.     filler = ' ';
  44.     strcpy(copy, str);            /* Copy str to copy */
  45.  
  46.     if (strlen(copy) >= width)        /* Test for str longer than width */
  47.     copy[width] = '\0';        /* Terminate it at width */
  48.  
  49.     strcpy(buf, char_str( (width - strlen(copy) ) >> 1, filler));
  50.     strcat(buf, copy);
  51.     i = strlen(buf);
  52.  
  53.     while (width - i)
  54.      buf[i++] = filler;
  55.  
  56.     buf[i] = '\0';
  57.  
  58.     return(buf);
  59. }
  60.  
  61.  
  62.  
  63. char *trim(char *str)            /* Trim spaces from end of string */
  64. {
  65.     static char buf[BUF];        /* Location of finished string */
  66.     char filler;
  67.     int i;
  68.  
  69.     filler = ' ';
  70.     strcpy(buf, str);
  71.     i = strlen(buf);
  72.  
  73.     while (buf[--i] == filler)
  74.     buf[i] = '\0';
  75.  
  76.     return(buf);
  77. }
  78.  
  79.  
  80.  
  81. char *char_str(int length, char c)
  82. {
  83.     static char loc[BUF];
  84.     char *ptr = loc;
  85.  
  86.     while (length--)
  87.     *ptr++ = c;
  88.  
  89.     *ptr = '\0';
  90.  
  91.     return(loc);
  92. }
  93.  
  94.  
  95.  
  96. int get_int(int defalt, int digits, int lowest, int highest)
  97. /*  defalt,    default value when C/R alone is struck */
  98. /*  digits,    maximum number of digits accepted */
  99. /*  lowest,    lowest value accepted */
  100. /*  highest;    highest value accepted */
  101. {
  102.     char buffer[80];            /* Buffer to store input string */
  103.     int ch;                /* All purpose character ch */
  104.     int index = 0;            /* Character array index */
  105.     int value = 0;            /* Value to return */
  106.     int done = FALSE;            /* Done/Not Done Flag */
  107.     char dfalt[10];            /* Buffer to store default value */
  108.                     /* as string */
  109.     int i, ii;                /* Length of default val as a string */
  110.  
  111.     sprintf(dfalt, "%d", defalt);    /* Convert default to string */
  112.     i = ii = strlen(dfalt);        /* Calculate its length */
  113.     printf("%s", dfalt);        /* Display default value */
  114.  
  115.     while (ii--)
  116.     putch('\b');            /* Backspace to beginning */
  117.  
  118.     while (!done)
  119.     {
  120.     while (index < digits)      /* While not enough digits, grab 'em */
  121.     {
  122.         ch = getch();          /* Get a char from console, no echo */
  123.  
  124.         if (isdigit(ch))        /* Digit!! so . . .  */
  125.         {
  126.         putch(ch);        /* Echo it to console, and */
  127.         buffer[index++] = ch;    /* Stuff it into buffer */
  128.  
  129.         if (index == 1)         /* Entered first digit, so. . . */
  130.         {
  131.             for (ii = digits;
  132.              --ii;
  133.                  )
  134.             putch(' ');    /* Blank it out */
  135.  
  136.             for (ii = digits;
  137.              --ii;
  138.                  )
  139.             putch('\b');    /* Backspace to beginning */
  140.         }
  141.         }
  142.  
  143.         else
  144.         if ( ch == '\b' &&         /* Backspace? */
  145.          index       )        /* if index not zero */
  146.         {
  147.         --index;        /* Reduce index */
  148.         putch(' ');        /* Blank it */
  149.         putch('\b');        /* Backspace over blank */
  150.         putch(ch);        /* Echo it to console */
  151.         }
  152.  
  153.         else
  154.         if (ch == '\033')        /* Escape */
  155.         exit(0);        /* says he's through */
  156.         else
  157.         if (ch == '\r')        /* Return? */
  158.         break;            /* says he's through */
  159.     }    /* End while not enough digits, grab 'em */
  160.  
  161.     buffer[index] = '\0';        /* Terminate string */
  162.  
  163.     if (index == 0)            /* No digits entered before return */
  164.     {
  165.         value = defalt;        /* So use default */
  166.         done  = TRUE;        /* We're through */
  167.     }
  168.     else                /* Some digits were entered */
  169.     {
  170.         value = atoi(buffer);    /* Convert string to integer */
  171.  
  172.         if (value < lowest ||    /* Range test value returned */
  173.         value > highest )
  174.         {                /* Out of allowable range. . . */
  175.         for (        ;
  176.                index;
  177.              --index )
  178.             putch('\b');    /* Backspace to beginning */
  179.  
  180.         for (ii = digits;
  181.              ii;
  182.              --ii)
  183.             putch(' ');        /* Blank it out */
  184.  
  185.         for (ii = digits;
  186.              ii;
  187.              --ii)
  188.             putch('\b');    /* Backspace to beginning */
  189.  
  190.         printf("%s", dfalt);    /* Display default value */
  191.  
  192.         for (ii = i;
  193.              ii;
  194.               --ii)
  195.             putch('\b');    /* Backspace to beginning */
  196.         }
  197.         else
  198.         done  = TRUE;        /* We're through */
  199.     }
  200.     }        /* end while !done */
  201.     return(value);
  202. }
  203.  
  204.  
  205.  
  206. int get_yn(char defalt)
  207. {
  208.     char c;                /* all purpose character */
  209.  
  210.     fputs(" (y/n) ? ", stderr);     /* Prompt for Yes or No */
  211.     putch(defalt);            /* Display default */
  212.     putch('\b');            /* Backspace to it */
  213.  
  214.     do
  215.     c = tolower(getch());        /* Get a char, make it lowercase */
  216.     while ( c != 'y'    &&        /* Until we get a y, n, ESC, */
  217.         c != 'n'    &&
  218.         c != '\033' &&
  219.         c != '\r'    );        /* or Return */
  220.  
  221.     if (c == '\033')            /* Escape */
  222.     exit(0);            /* says he's through */
  223.     else
  224.     if (c == '\r')            /* If a return, make it the default */
  225.     c = defalt;
  226.  
  227.     putch(c);                /* Display choice to user */
  228.  
  229.     return (c == 'y') ?
  230.          TRUE :
  231.         FALSE  ;
  232. }
  233.  
  234.  
  235.  
  236. void hold(void)
  237. {
  238.     fputs("\nPrinter ready?  Any key to continue. . . ", stderr);
  239.     getch();
  240. }
  241.  
  242.  
  243.  
  244. void signon(void)
  245. {
  246.     fprintf(stderr,
  247. "\t\t\tYEARCAL v0.17T %s @ %s\n\n", __DATE__, __TIME__);
  248.     fputs(
  249. "\t\tCopyright 1987, 1988, 1989 by Paul M. Sittler\n\n"
  250.  
  251. "\tYEARCAL makes calendars (A/M) or schedules (W/D) for years after 1582.\n\n"
  252.  
  253. "\tAt the user's option, Normal, Fiscal Year, AGGIE, or 3-Digit Julian\n"
  254. "\tDate Calendars can be produced, in multiple copies, for a number of\n"
  255. "\tconsecutive years, or both.  Fiscal Year calendars may be produced for\n"
  256. "\tany arbitrary 12 or 13 month fiscal year.  The user may select a\n"
  257. "\tProgrammer's calendar, numbered in Hexadecimal or Octal numbers rather\n"
  258. "\tthan decimal numbers, and may choose one of several languages.\n\n"
  259. "\tThe calendars may be displayed on the screen, printed, or written to\n"
  260. "\ta file as desired.  If written to disk, files are named like YYYY.ENG\n"
  261. "\t(Normal ENGlish), YYYYFY.DUT (Fiscal-Year DUTch), YYYYAGG.TEX (Aggie-\n"
  262. "\ttype TEXan), or YYYYJUL.POL (3-Digit Julian Date POLish) calendars,\n"
  263. "\tetc.  Hex or Octal calendar files will have an \"H\" or \"O\" added to\n"
  264. "\ttheir names, such as YYYYH.SPA, YYYYFYO.SER or YYYYAGGH.FRE.\n\n"
  265.  
  266. "\tYEARCAL may be freely distributed, and used for non-commercial\n"
  267. "\tpurposes, as long as the unmodified program source code and\n"
  268. "\tdocumentation files are distributed with it.\n", stderr);
  269. }
  270.  
  271.  
  272.  
  273. void setup_files(char out)
  274. {
  275.     if (fp)
  276.     fflush(fp);
  277.  
  278.     if (out == 'V')
  279.     {
  280.     if (!strcmp(file, "PRN"))
  281.         fclose(fp);
  282.  
  283.     if (strcmp(file, "CON"))
  284.     {
  285.         strcpy(file, "CON");
  286.         fp = fopen(file, "w");
  287.     }
  288.     }
  289.     else
  290.     if (out == 'P')
  291.     {
  292.     if (!strcmp(file, "CON"))
  293.         fclose(fp);
  294.  
  295.     if (strcmp(file, "PRN"))
  296.     {
  297.         strcpy(file, "PRN");
  298.         fp = fopen(file, "w");
  299.     }
  300.     }
  301. }
  302.  
  303.  
  304.  
  305. /************************************************************************/
  306. void get_opts(char *name)
  307. /* char *name    filename from argv[0] */
  308. {
  309.     /* Various statistics (such as the last time the program was run)
  310.     * are stored in a buffer at the end of the executable structure.
  311.     * These stats and the settings for user selected options are all
  312.     * stored in the "options" structure.  This function creates the
  313.     * data area if it doesn't exist and initializes Opt as appropriate.
  314.     * Alan Holub, C-Chest, DDJ Feb 1988.
  315.     */
  316.  
  317.     int fd;                /* file descriptor handle */
  318.     int i, *p;                /* used to create checksum */
  319.  
  320.     if ( (fd = open( name, O_RDWR | O_BINARY ) ) == ERROR)
  321.     {
  322.     perror( name);
  323.     exit(1);
  324.     }
  325.  
  326.     lseek(fd, 0L - sizeof(Opt), SEEK_END);
  327.  
  328.     /* Check to see if all of the options area is still there */
  329.     if ( read(fd, (char *) &Opt, sizeof(Opt) ) != sizeof(Opt) )
  330.     ferr( "Internal error:  Can't read options\n");
  331.  
  332.     /* Check to see if the signature is still as it should be */
  333.     if (strcmp( DEF_SIG, Opt.signature) != 0)
  334.     {
  335.     memset( &Opt, 0, sizeof(Opt));
  336.     /* The memset is for debugging.  It shows us that the record has
  337.      * been written correctly.
  338.      */
  339.  
  340.     strcpy( Opt.signature, DEF_SIG);
  341.  
  342.         /* Initialize other fields in the Opt structure here. */
  343.         Opt.aggie    = FALSE;    /* Not all are Aggies! */
  344.     Opt.bh        =  6;        /* Hour defaults to 0600 */
  345.     Opt.copies    =  1;        /* At least one copy. . . */
  346.     Opt.fy        = FALSE;    /* Most are not Fiscal Year */
  347.     Opt.indent      =  7;        /* Left Margin Indent in spaces */
  348.     Opt.julian    = FALSE;    /* Regular calendar is default */
  349.     Opt.lang    =  7;        /* Select English as default Language */
  350.     Opt.lds        =  0;        /* Select ASCII for line drawing Set */
  351.     Opt.more_yrs    =  0;        /* One period at a time. . . */
  352.     Opt.nh        = 24;        /* Scheduled Hour defaults to 24 */
  353.     Opt.pause    = FALSE;    /* No pause at end of each printed page */
  354.     Opt.mil        = TRUE;        /* Military (24-hour) time */
  355.     Opt.pl        = 66;        /* Page Length in lines */
  356.     Opt.pw        = 80;        /* Page Width in characters or columns */
  357.     Opt.base    = FALSE;    /* Decimal for most */
  358.     Opt.sched_type     = FALSE;    /* Annual calendar is default */
  359.  
  360.     for (i = 0;            /* Initialize title array */
  361.              i < 8;
  362.              i++)
  363.         Opt.title[i][0] = '\0';
  364.  
  365.     Opt.chksum = 0;
  366.  
  367.         for (p = (int *)(&Opt), i = sizeof(Opt) / 2;
  368.              --i >= 0;
  369.               )
  370.             Opt.chksum -= *p++;
  371.  
  372.         lseek(fd, 0L, SEEK_END);
  373.  
  374.     if (write(fd, (char *) &Opt, sizeof(Opt)) != sizeof(Opt) )
  375.         ferr("Internal error:  Can't initialize options\n");
  376.     }
  377.     close(fd);
  378. }
  379.  
  380.  
  381.  
  382. void put_opts(char *name)
  383. {
  384.     /* Update the options buffer at the end of the .EXE program (which
  385.      * better exist).  If the options buffer doesn't exist, this function
  386.      * will destroy the end of the file.  Alan Holub, C-Chest, DDJ Feb 1988.
  387.      */
  388.  
  389.     int fd;                /* file descriptor handle */
  390.     int i, *p, checksum;        /* used to create checksum */
  391.  
  392.     if ( (fd = open( name, O_RDWR | O_BINARY) ) == -1)
  393.     {
  394.     perror( name );
  395.     exit(1);
  396.     }
  397.  
  398.     /* Recompute the checksum */
  399.  
  400.     checksum = 0;
  401.  
  402.     for (p = (int *)(&Opt), i = sizeof(Opt) / 2;
  403.        --i >= 0;
  404.           )
  405.     checksum -= *p++;
  406.  
  407.     if (checksum != Opt.chksum)
  408.     printf("\tDefaults have been changed.");
  409.  
  410.     Opt.chksum = checksum;
  411.  
  412.     lseek(fd, 0L - sizeof(Opt), SEEK_END);
  413.  
  414.     if (write(fd, (char *) &Opt, sizeof(Opt)) != sizeof(Opt) )
  415.     ferr("Can't do final options update\n");
  416.  
  417.     close(fd);
  418. }
  419.  
  420.  
  421.  
  422. void ferr(char *fmt)
  423. {
  424.     /* ferr() is used for fatal error processing.  It is used just like
  425.      * printf().  However, it exits the program with a status of 1
  426.      * immediately after printing the message.  I'm using ANSI, not UNIX
  427.      * variable argument conventions here.  (Alan Holub, C-Chest Book, p. 299)
  428.      */
  429.  
  430.     va_list args;
  431.     va_start(args, fmt);
  432.     vfprintf(stderr, fmt, args);
  433.     exit(1);
  434. }
  435.  
  436.  
  437.  
  438. void prep_cal(int year)
  439. {
  440.     int count,                /* Count of the days */
  441.     day,                /* Weekday Sun=0, Mon=2, ... Sat=6 */
  442.     month,                /* Month Jan=0, Feb=1, ... Dec=11 */
  443.     week,                /* Six weeks/month possible */
  444.     yeer,                /* Year for calendar */
  445.     y;                /* Year Last=0, This=1, Next=2 */
  446.  
  447.     for (y = 0;                /* Start at last year y[0] */
  448.      y < 3;                /* Stop after next year y[2] */
  449.      y++)
  450.     {
  451.     yeer = (year + y - 1);
  452.  
  453.     if (leap(yeer))            /* Tidy up month length array */
  454.         mon[1].length = 29;     /* For this year by fixin' Feb. . . */
  455.     else
  456.         mon[1].length = 28;
  457.  
  458.     /* Get weekday of first day of each month, put into array mon */
  459.     /*   Jan = 0, Feb = 1, Mar = 2, Apr = 3, . . .  Dec = 11 */
  460.     /*   Su = 0, Mo = 1, Tu = 2, We = 3, Th = 4, Fr = 5, Sa = 6 */
  461.     for (month =  0;
  462.          month < 12;        /* 12 months/year */
  463.          month++   )
  464.         mon[month].first_day = weekday(yeer, month + 1, 1);
  465.  
  466.     /* Form year array with 0 for unused dates, with dates */
  467.     /*   in their relative positions by weekday */
  468.     for (month = 0;
  469.          month < 12;        /* 12 months/year */
  470.          month++)
  471.     {
  472.         count = 0;            /* Set day counter to 0 */
  473.  
  474.         for (week = 0;
  475.          week < 6;        /* 6 weeks/month */
  476.          week++)
  477.         {
  478.         for (day = 0;
  479.              day < 7;        /* 7 days/week */
  480.              day++)
  481.         {
  482.             if (week == 0                 &&    /* 1st week of month */
  483.             day < mon[month].first_day )    /* Before 1st day */
  484.             yr[y][month][week][day] = 0;    /* Zero it */
  485.             else
  486.             if (++count <= mon[month].length)   /* Not past EOMonth */
  487.             yr[y][month][week][day] = count;
  488.             else
  489.             yr[y][month][week][day] = 0;    /* Zero it */
  490.         }
  491.         }
  492.     }
  493.     }
  494. }
  495.  
  496.  
  497.  
  498. /* Function to get day of week from YYYY, MM, DD as integers */
  499. /* This uses the Zeller Congruence algorithm, as shown in:  */
  500. /*   Radcliffe, Robert A. & Raab, Thomas J., "Data Handling Utilities in C", */
  501. /*   1986, SYBEX Books, 2344 Sixth Street, Berkeley, CA 94710. */
  502. /* Explanation of algorithm is in:  Uspensky & Heaslet, */
  503. /*   "Elementary Number Theory", Appendix A:  Calendar Problems */
  504. /* Discussion of Zeller Congruence in: */
  505. /*  "Day of the Week Revisited", Computer Language, Dec 1988, pp 35-38. */
  506. /* Discussion also in Computer Languages Magazine, Feb 1989, p 9 in a */
  507. /*   letter from Bob Whitefield. */
  508. /* For MM:  Jan = 1, Feb = 2, Mar = 3, Apr = 4, . . .  Dec = 12 */
  509. int weekday(int YYYY, int MM, int DD)
  510. {
  511.     int day_of_week,            /* Su = 0, Mo = 1, . . . Sa = 6 */
  512.     y,                      /* Year adj for Zeller congruence */
  513.     m,                /* Month adj for Zeller congruence */
  514.     dy,                /* Decimal year, 2-digits like '89 */
  515.     c;                /* Century 2-digits, like 19xx */
  516.  
  517.     if (MM > 2)                /* After February, so decrement */
  518.     {
  519.     m = MM - 2;            /* Run year from March to February */
  520.     y = YYYY;            /* Keep YYYY value same */
  521.     }
  522.     else                /* Month is January or February */
  523.     {
  524.     m = MM + 10;            /* Make them the 11th and 12th */
  525.                     /*   months respectively */
  526.     y = YYYY - 1;            /* So we have one less year */
  527.     }
  528.  
  529.     c  = y / 100;            /* Get century number */
  530.     dy = y - (100 * c);            /* Decimal year */
  531.     day_of_week = ( (13 * m - 1) / 5)
  532.           + DD + dy + (dy / 4)
  533.           + (c / 4) - c - c + 77;
  534.     day_of_week = day_of_week - 7 * (day_of_week / 7);
  535.  
  536.     return(day_of_week);
  537. }
  538.  
  539.  
  540.  
  541. /* Function to decide if a year is a leap year */
  542. int leap(int years)
  543. {                    /* Leap year sieve */
  544.     if (years & 0x0003)         /* Mask year to see if not leap year */
  545.        return FALSE;            /* If we look at the last two bits,  */
  546.                     /* and one of them is on, then the   */
  547.                     /* year can't be divisible by four.  */
  548.                     /* Thus it is not a leap year, so    */
  549.                     /* function returns FALSE.           */
  550.                     /* Test for the leap century.        */
  551.     else                /* Leap century:   years that are:   */
  552.     if (!(years % 100) &&         /* evenly divisible by 100:          */
  553.                     /*   not leap years unless also      */
  554.      (years % 400) )        /*   evenly divisible by 400.        */
  555.     return FALSE;            /* Gruenberger and Jaffray,          */
  556.                     /* "Problems for Computer Solution", */
  557.                     /* Wiley, 1965. */
  558.                     /* We have filtered out all years    */
  559.                     /* that are not evenly divisible by  */
  560.                     /* four as well as those evenly      */
  561.                     /* divisible by 100 that are evenly  */
  562.                     /* divisible by 400. */
  563.                     /* It seems that all the rest are    */
  564.                     /*   (a) evenly divisible by four    */
  565.                     /*   (b) evenly divisible by 400     */
  566.     return TRUE;            /*   (c) Thus, leap years. . . */
  567. }
  568.  
  569.  
  570.  
  571.